package com.fakeDYChat.common.user.service.impl;

import cn.hutool.core.thread.NamedThreadFactory;
import cn.hutool.http.HttpUtil;
import com.fakeDYChat.common.common.domain.vo.resp.ApiResult;
import com.fakeDYChat.common.common.utils.JsonUtils;
import com.fakeDYChat.common.user.dao.UserDao;
import com.fakeDYChat.common.user.domain.entity.IpDetail;
import com.fakeDYChat.common.user.domain.entity.IpInfo;
import com.fakeDYChat.common.user.domain.entity.User;
import com.fakeDYChat.common.user.service.IpService;
import com.fasterxml.jackson.core.type.TypeReference;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class IpServiceImpl implements IpService, DisposableBean {

    public static final int MAIN_CORE = 1;
    public static final int MAX_CORE = 1;
    public static final int MAX_IP_POOL_SIZE = 500;
    public static final String GET_IP_INFO_URL = "https://ip.taobao.com/outGetIpInfo?ip=%s&accessKey=alibaba-inc";
    public static final int SLEEP_TIME = 2000;

    //单线程排队线程池
    private ExecutorService executorService = new ThreadPoolExecutor(MAIN_CORE, MAX_CORE,
            0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(MAX_IP_POOL_SIZE),
            new NamedThreadFactory("refresh-ipDetail", false));
    private final UserDao userDao;

    public IpServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void refreshIpDetailAsync(Long uid) {
        executorService.submit(() -> {
            User user = userDao.getById(uid);
            IpInfo ipInfo = user.getIpInfo();
            if (Objects.isNull(ipInfo)) {
                return;
            }
            String needRefreshIp = ipInfo.needRefreshIp();
            //判断是否需要刷新ip信息
            if (StringUtil.isBlank(needRefreshIp)) {
                return;
            }
            //执行刷新ip信息逻辑
            IpDetail ipDetail = tryGetIpDetailOrNullTreeTimes(needRefreshIp);
            if (Objects.nonNull(ipDetail)) {
                ipInfo.refreshIpDetail(ipDetail);
                User update = new User();
                update.setId(user.getId());
                update.setIpInfo(ipInfo);
                userDao.updateById(update);
            }
        });
    }

    private IpDetail tryGetIpDetailOrNullTreeTimes(String needRefreshIp) {
        try {
            //重试三次
            for (int i = 0; i < 3; i++) {
                //获取到了ip解析结果
                IpDetail ipDetail = getIpDetailOrNull(needRefreshIp);
                if (Objects.nonNull(ipDetail)) {
                    return ipDetail;
                }
                Thread.sleep(SLEEP_TIME);
            }
            return null;
        } catch (Exception e) {
            log.error("tryGetIpDetailOrNullTreeTimes Exception", e);
            return null;
        }
    }

    /**
     * 请求并解析ip解析结果
     *
     * @param needRefreshIp
     * @return com.fakeDYChat.common.user.domain.entity.IpDetail
     * @author Tang
     * @date 2024/1/7 21:20
     **/
    private IpDetail getIpDetailOrNull(String needRefreshIp) {
        //请求解析
        String data = HttpUtil.get(String.format(GET_IP_INFO_URL, needRefreshIp));
        //获取解析结果
        ApiResult<IpDetail> result = JsonUtils.toObj(data, new TypeReference<ApiResult<IpDetail>>() {
        });
        return result.getData();
    }

    @Override
    public void destroy() throws Exception {
        executorService.shutdown();
        if (!executorService.awaitTermination(30, TimeUnit.SECONDS)) {
            if (log.isErrorEnabled()) {
                log.error("Time out while waiting for executor [{}] to terminate", executorService);
            }
        }
    }
}
